//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <PowerInc.h>

_ELASTOS_NAMESPACE_USING

#include <VirtualDevice.h>
#include <TimeManager.h>

extern CVirtualDevice * g_display;
//object copy maybe a waste of time.handle it later!
ECode CVirtualDevice::Read(
    /* [in] */ Int64 u64Offset,
    /* [in] */ Int32 bytesToRead,
    /* [out] */ MemoryBuf * pBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    ECode ec;
    if (this != g_display) {
        if(PowerState < (unsigned long)DeviceLowPower)
            SetPowerMode((UInt32)DevicePowerOn);
        ec = piRealdev->Read(u64Offset, bytesToRead, pBuffer,
            ppCompletionEvent);
        if (FAILED(ec)) return ec;
        RestartTimer();
    }
    else {
        ec = piRealdev->Read(u64Offset, bytesToRead, pBuffer,
            ppCompletionEvent);
        if (FAILED(ec)) return ec;
    }
    return NOERROR;
}

ECode CVirtualDevice::Write(
    /* [in] */ Int64 u64Offset,
    /* [in] */ const MemoryBuf & buffer,
    /* [out] */ Int32 * pBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    ECode ec;
    if (this != g_display) {
        if(PowerState < (unsigned long)DeviceLowPower)
            SetPowerMode((UInt32)DevicePowerOn);
        ec = piRealdev->Write(u64Offset, buffer, pBytesWritten,
            ppCompletionEvent);
        if (FAILED(ec)) return ec;
        RestartTimer();
    }
    else {
        ec = piRealdev->Write(u64Offset, buffer, pBytesWritten,
            ppCompletionEvent);
        if (FAILED(ec)) return ec;
    }
    return NOERROR;
}

ECode CVirtualDevice::Control(
    /* [in] */ Handle32 nControlCode,
    /* [in] */ const MemoryBuf & inBuffer,
    /* [out] */ MemoryBuf * pOutBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    ECode ec;
    if (this != g_display) {
        if (PowerState < (unsigned long)DeviceLowPower) {
            SetPowerMode((UInt32)DevicePowerOn);
        }
        ec = piRealdev->Control(nControlCode, inBuffer, pOutBuffer,
            ppCompletionEvent);
        if (FAILED(ec)) return ec;
        RestartTimer();
    }
    else {
        ec = piRealdev->Control(nControlCode, inBuffer, pOutBuffer,
            ppCompletionEvent);
        if (FAILED(ec)) return ec;
    }
    return NOERROR;
}

void DM_ChangeMode(void * pdevice);
CVirtualDevice::CVirtualDevice(UInt32 deviceID, IInterface * pObject)
{
    PowerState=DeviceSuspend;//at first:standby.
    SpecifiedMode=5;//set an illegal mode,means user app not specified one.
    ModeChangeInterval=12;//default 12s,which is from lcd.
    KeepOn=FALSE;
    piRealdev=(IDeviceDriver *)pObject;
    DeviceID=deviceID;
    PowerCreateTimer(&hTimer, 1, ModeChangeInterval, DM_ChangeMode,
        (void *)this);//s
}

void CVirtualDevice::RestartTimer()
{
    PowerReStartTimer(hTimer,ModeChangeInterval);
}

EXTERN_C void Power_UpdateDevicePower(int DeviceID,unsigned long Mode);
ECode CVirtualDevice::SetPowerMode(UInt32 mode)
{
    ECode ec = SetMode(mode);
    if (PowerState < (UInt32)DevicePowerOff
            || PowerState > (UInt32)DevicePowerOn)
        return E_ACCESS_DENIED;
    Power_UpdateDevicePower(DeviceID,PowerState);//for emulator only
    //if(PowerState!=(UInt32)DevicePowerOff)RestartTimer();
    return ec;
}

ECode CVirtualDevice::SetMode(UInt32 mode)
{
    MemoryBuf ebbintOut((Byte *)&PowerState, 4, 4);
    MemoryBuf_<4> ebbintIn;
    ebbintIn.Copy((Byte *)&mode, sizeof(int));
    ECode ec = piRealdev->Control(
                1000+mode, ebbintIn, &ebbintOut, NULL );
    return ec;
}
void CVirtualDevice::UpdateInputLastUse()
{
    printf("update last use\n");
    if(KeepOn)return;
    if (SpecifiedMode == 5) {    //user app not specfied,use mode 2.
        SpecifiedMode=DeviceSuspend;
    }
    SetPowerMode((UInt32)SpecifiedMode);
    //for lcd ect.,a little different from common device like audio card.
    if(SpecifiedMode != (UInt32)DevicePowerOff)RestartTimer();
}

ECode CVirtualDevice::ChangeMode()
{
    ECode ec = NOERROR;
    if (PowerState == (UInt32)DevicePowerOn) {
        ec = SetPowerMode((UInt32)DeviceLowPower);
        //later changed,coz these implement can't handle concurrent
        //timer callback and deffiency.
        RestartTimer();
        return ec;
    }
    if (PowerState == (UInt32)DeviceLowPower) {
        ec = SetPowerMode((UInt32)DeviceSuspend);
        RestartTimer();
        return ec;
    }
    if (PowerState == (UInt32)DeviceSuspend) {
        ec = SetPowerMode((UInt32)DeviceVeryLowPower);
        RestartTimer();
        return ec;
    }
    if (PowerState == (UInt32)DeviceVeryLowPower) {
        ec = SetPowerMode((UInt32)DevicePowerOff);
        PowerStopTimer(hTimer);
        return ec;
    }
    return ec;
}

void CVirtualDevice::InitDevPowerMode(UInt32 Mode)
{
    if(Mode <= (UInt32)DevicePowerOff || Mode > (UInt32)DevicePowerOn)return;
    SpecifiedMode=Mode;
    SetPowerMode((UInt32)SpecifiedMode);
}

void CVirtualDevice::KeepSpecifiedMode(UInt32 Mode, _ELASTOS Boolean KeepOn)
{
    this->KeepOn=KeepOn;
    if (KeepOn) {
        SetPowerMode(Mode);
        PowerStopTimer(hTimer);//stop the timer,keep the specified mode
    }
    else {    //the user app want to use system power mode adjusting.
        SetPowerMode(Mode);
        if(Mode != (UInt32)DevicePowerOff)RestartTimer();
    }
}

void CVirtualDevice::SetChangeModeInterval(UInt32 Interval)
{
    ModeChangeInterval=Interval;
}

void DM_ChangeMode(void * pdevice)
{
    printf("dm_change mode\n");
    CVirtualDevice * prdev=(CVirtualDevice *)pdevice;
    prdev->ChangeMode();
}
